/* Copyright (C) 2012  	Mathieu Marleix <mathieu.marleix@aerian.fr>
 * 						Sébastien Dufay
 * 						Romain Noel
 * 						Nicolas Dennewald
 * 						Slim Aloui
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.esiee.mobiliteam;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URL;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.esiee.mobiliteam.data.RSSFeed;
import org.esiee.mobiliteam.data.RSSItem;
import org.esiee.mobiliteam.handler.RSSHandler;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;

/**
 * Classe de gestion de l'affichage graphique de la liste de l'agenda.
 * @author Mathieu Marleix
 * @author Sébastien Dufay
 * @author Romain Noel
 * @author Nicolas Dennewald
 * @author Slim Aloui
 */
public class RssActivity extends Activity implements OnItemClickListener {
	public String RSS_URL = "NULL";
	public static final String PREFS_NAME = "Prefs_file";
	public final String tag = "RSSReader";
	private RSSFeed feed = null;
	private Date lastDateRss = null;
	static final int ALARM_ID = 1234567;
	private static final Exception Exception = null;
	static Alarm alarm;
	private SharedPreferences sharedPrefs;
	public Locale locale = null;
	private ListView itemlist = null;
	private boolean listPrint = false, taskEnd = false, DEBUG = true;
	private ProgressDialog mProgressDialog;

	@Override
	public void onConfigurationChanged(Configuration newConfig)
	{
		super.onConfigurationChanged(newConfig);
		if (locale != null)
		{
			newConfig.locale = locale;
			Locale.setDefault(locale);
			getBaseContext().getResources().updateConfiguration(newConfig, getBaseContext().getResources().getDisplayMetrics());
		}
		loadRessources();
	}
	@Override
	public void onCreate(Bundle bundle)
	{
		super.onCreate(bundle);

		sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
		SharedPreferences.Editor memory = sharedPrefs.edit();
		memory.putString("dateLastRss" , RSSFeed.dateToString(new Date()));
		memory.commit();
		changeLocales();
		setContentView(R.layout.main);
		
		mProgressDialog = ProgressDialog.show(this,getString(R.string.loading),"List loading",true);
		
		Thread thread = new Thread(new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				loadRessources();
			}
		});
		thread.start();
	}
	/**
	 * Permet de changer la langue de l'application independamment de
	 * la locale de la machine.
	 */
	public void changeLocales(){
		Configuration config = getBaseContext().getResources().getConfiguration();

		String lang = sharedPrefs.getString("languages", "");
		if(DEBUG) System.out.println(sharedPrefs.getString("languages", ""));
		if (! "".equals(lang) && ! config.locale.getLanguage().equals(lang))
		{
			locale = new Locale(lang);
			Locale.setDefault(locale);
			config.locale = locale;
			getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
		}
	}
	/**
	 * Lance le chargement des ressources en fonction de l'information stocké dans
	 * le champs ressource_ade du preference manager.
	 */
	public void loadRessources(){
		String ressources = sharedPrefs.getString("ressources_ade", "");
		String matcheressources = RSSHandler.matchedDate("([0-9,]*[0-9]{1,5})",ressources);

		if(matcheressources.equals("")){
			Intent intent = new Intent(this, SettingsActivity.class);
			Bundle bundle = new Bundle();
			//Add the parameters to bundle as
			bundle.putString("activityChoice", "RssActivity");
			bundle.putBoolean("erreur", true);
			intent.putExtras(bundle);
			startActivity(intent);
			finish();
			return;
		}
		else if(ressources.startsWith("http")){
			matcheressources = RSSHandler.matchedDate("resources=([0-9,]*[0-9]{1,5})",ressources);
			RSS_URL = "http://planif.esiee.fr:8080/ade/rss?projectId=4&resources=" + matcheressources
					+ "&nbDays=30&x=26&y=2";
			sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
			SharedPreferences.Editor memory = sharedPrefs.edit();
			memory.putString("urlSaved" , RSS_URL);
			memory.commit();
			listRssStorage();
			showListView();
		}
		else {
			RSS_URL = "http://planif.esiee.fr:8080/ade/rss?projectId=4&resources=" + matcheressources
					+ "&nbDays=30&x=26&y=2";
			sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
			SharedPreferences.Editor memory = sharedPrefs.edit();
			memory.putString("urlSaved" , RSS_URL);
			memory.commit();
			listRssStorage();
			showListView();
		}
		//RSS_URL = "http://planif.esiee.fr:8080/ade/rss?projectId=4&resources=2098%2C2609%2C2644%2C2658%2C3206%2C2664%2C2667%2C2666%2C2665%2C2994%2C3239%2C1716&nbDays=30&x=26&y=2";
		if(getFeed() != null){
			boolean alarm_on = sharedPrefs.getBoolean("perform_alarm", false);

			if(alarm_on) {
				while(!getFeed().isSortedNotEmpty())
					try {
						wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				if(!lastDateRss.after(new Date())){
					charger();
					planifierAlarm();
				}
			}
		}
	}
	/**
	 * Gestion du stockage persistant de la liste du flux RSS.
	 * Celle-ci se recharge toute les 10h.
	 */
	public void listRssStorage(){
		try {
			//On va chercher dans le fichier de preference la derniere date stockee.
			lastDateRss = RSSFeed.stringToDate(sharedPrefs.getString("dateLastRss", null));
			lastDateRss.setHours(lastDateRss.getHours()+Integer.parseInt(sharedPrefs.getString("synchro", "10")));
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			if(DEBUG) System.out.println("Reading file error\n");
			e.printStackTrace();
		}
		if(DEBUG) System.out.println("Dates - now: "+ new Date() + " now + 10h: " + lastDateRss.toGMTString() + "\n");
		//On la compare avec celle de maintenant.
		if(lastDateRss.after(new Date()) || !sharedPrefs.getBoolean("perform_synchro", true)){
			if(DEBUG) System.out.println("is after? True \n");
			//On tente de recharger la sauvegarde. Si celle-ci n'existe pas on la cree.
			try {
				setFeed( (RSSFeed) loadClassFile(new File(this.getCacheDir(),"rss.bin")));
				if(getFeed() == null) throw Exception;
				if(getFeed().isSortedNotEmpty()&& sharedPrefs.getBoolean("perform_synchro", true)){
					if(DEBUG) System.out.println("Feed is empty...\n");
					reloadList();
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				if(DEBUG) System.out.println("Sorted Exception\n");
				if(sharedPrefs.getBoolean("perform_synchro", true)){
					reloadList();
				}
				else {
					runOnUiThread(new Runnable() {

						@Override
						public void run() {
							// TODO Auto-generated method stub
							setListPrint(true);
							TextView textview = (TextView) findViewById(R.id.content_rssActivity);
							textview.setText(getString(R.string.error_rss) + ": " + getString(R.string.no_synchro));
						}
					});
				}

				e.printStackTrace();
			}
		}
		else{
			if(sharedPrefs.getBoolean("perform_synchro", true)){
				if(DEBUG) System.out.println("is after? False \n");
				reloadList();
			}
			else{
				runOnUiThread(new Runnable() {

					@Override
					public void run() {
						// TODO Auto-generated method stub
						setListPrint(true);
						TextView textview = (TextView) findViewById(R.id.content_rssActivity);
						textview.setText(getString(R.string.error_rss) + ": " + getString(R.string.no_synchro));
					}
				});
			}
		}
	}
	/**
	 * Reload the feed.
	 */
	public void reloadList(){
		setFeed(getFeed(RSS_URL));
		saveClassFile(getFeed());
	}
	/**
	 * Chargement d'un objet ecrit dans un fichier.
	 * @param f : fichier où est stocké l'objet.
	 * @return : l'objet
	 * @throws Exception
	 */
	public Object loadClassFile(File f) throws Exception
	{
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
		Object o = ois.readObject();
		return o;
	}
	/**
	 * Fonction de sauvegarde d'objet sur l'espace disque.
	 * @param o : l'objet à sauver.
	 */
	public void saveClassFile(Object o){
		boolean mExternalStorageAvailable = false;
		boolean mExternalStorageWriteable = false;
		String state = Environment.getExternalStorageState();

		if (Environment.MEDIA_MOUNTED.equals(state)) {
			// We can read and write the media
			mExternalStorageAvailable = mExternalStorageWriteable = true;
		} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
			// We can only read the media
			mExternalStorageAvailable = true;
			mExternalStorageWriteable = false;
		} else {
			// Something else is wrong. It may be one of many other states, but all we need
			//  to know is we can neither read nor write
			mExternalStorageAvailable = mExternalStorageWriteable = false;
		}
		if(mExternalStorageAvailable && mExternalStorageWriteable){
			ObjectOutputStream oos;
			try {
				oos = new ObjectOutputStream(new FileOutputStream(new File(this.getCacheDir(),"rss.bin"))); //Select where you wish to save the file...
				oos.writeObject(o); // write the class as an 'object'
				oos.flush(); // flush the stream to insure all of the information was written to 'save.bin'
				oos.close();// close the stream
				if(DEBUG) System.out.println("Saved! \n");
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				if(DEBUG) System.out.println("Writing file error\n");
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	/**
	 * Fonction récupérant le flux RSS.
	 * @param urlString : url à checker.
	 * @return le flux de type RSSHandler.
	 */
	private RSSFeed getFeed(String urlString)
	{
		try
		{
			URL url = new URL(urlString);

			SAXParserFactory factory = SAXParserFactory.newInstance();
			SAXParser parser = factory.newSAXParser();
			XMLReader xmlreader = parser.getXMLReader();

			RSSHandler rssHandler = new RSSHandler();
			xmlreader.setContentHandler(rssHandler);

			InputSource is = new InputSource(url.openStream());    
			xmlreader.parse(is);

			return rssHandler.getFeed();
		}
		catch (Exception ee)
		{
			return null;
		}
	}
	/**
	 * Affiche la liste des objets du flux.
	 */
	private void showListView()
	{

		if (getFeed() == null)
		{
			runOnUiThread(new Runnable() {

				@Override
				public void run() {
					// TODO Auto-generated method stub
					setListPrint(true);
					TextView textview = (TextView) findViewById(R.id.content_rssActivity);
					textview.setText(getString(R.string.error_rss));
				}
			});
			return;
		}

		final SimpleAdapter adapter = new SimpleAdapter(this, getFeed().getAllItemsForListView(),
				android.R.layout.simple_list_item_2, new String[] { RSSItem.TITLE,RSSItem.DATE },
				new int[] { android.R.id.text1 , android.R.id.text2});
		setTaskEnd(false);

		runOnUiThread(new Runnable() {

			@Override
			public void run() {
				setListPrint(true);
				itemlist = (ListView) findViewById(R.id.itemlist);
				itemlist.setAdapter(adapter); 
				itemlist.setSelection(0);
				setTaskEnd(true);
			}
		});
		while(!isTaskEnd())
			try {
				Thread.sleep(10L);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		itemlist.setOnItemClickListener(this); 
	}
	/**
	 * Listener sur la liste des objets de la liste.
	 */
	public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
		// TODO Auto-generated method stub
		Intent itemintent = new Intent(this,ActivityShowDescription.class);

		Bundle b = new Bundle();
		b.putString("title", getFeed().getItem(position).getTitle());
		b.putString("description", getFeed().getItem(position).getDescription());
		b.putString("link", getFeed().getItem(position).getLink());
		b.putString("pubdate", getFeed().getItem(position).getPubDate());

		itemintent.putExtra("android.intent.extra.rssItem", b);
		startActivityForResult(itemintent, 0);
	}
	/**
	 * Methode de gestion du menu.
	 */
	public boolean onCreateOptionsMenu(Menu menu) {
		// refresh the tabs and their content
		//    	Toast.makeText(RSSFeed.this, "Option", Toast.LENGTH_SHORT).show();
		//Création d'un MenuInflater qui va permettre d'instancier un Menu XML en un objet Menu
		MenuInflater inflater = getMenuInflater();
		//Instanciation du menu XML spécifier en un objet Menu
		inflater.inflate(R.layout.menu, menu);
		return true;
	}
	/**
	 * Methode de gestion des clicks du menu.
	 */
	public boolean onOptionsItemSelected(MenuItem item) {
		//On regarde quel item a été cliqué grâce à son id et on déclenche une action
		switch (item.getItemId()) {
		case R.id.option:
			Intent intent = new Intent(this, SettingsActivity.class);
			Bundle bundle = new Bundle();
			//Add the parameters to bundle as
			bundle.putBoolean("erreur", false);
			bundle.putString("activityChoice", "RssActivity");
			intent.putExtras(bundle);
			startActivity(intent);
			finish();
			return true;
		case R.id.month_view:
			Date date = new Date();
			Intent intent3 = new Intent(this,TabWidget.class);
			intent3.setAction(CalendarActivity.MIME_TYPE);
			Bundle bundle2 = new Bundle();
			date.setDate(date.getDate());
			bundle2.putString("activityChoice", "CalendarActivity");
			bundle2.putInt("day", date.getDate());
			bundle2.putInt("month", date.getMonth());
			intent3.putExtras(bundle2);
			startActivity(intent3);
			finish();
			return true;
		case R.id.refresh_button:
			reloadList();
			Intent intent2 = new Intent(this, TabWidget.class);
			Bundle bundle3 = new Bundle();
			bundle3.putString("activityChoice", "RssActivity");
			intent2.putExtras(bundle3);
			startActivity(intent2);
			finish();
			return true;
		case R.id.list_view:
			return true;
		case R.id.quitter:
			finish();
			return true;
		}
		return false;
	}
	/**
	 * Chargement des informations du alarme.
	 * Ici pour la sauvegarde on déserialise l'objet Alarm.
	 */
	public void charger(){
		alarm = null;
		try {
			ObjectInputStream alarmOIS = new ObjectInputStream(openFileInput("alarm.serial"));
			alarm = (Alarm) alarmOIS.readObject(); 
			alarmOIS.close();
		}
		catch(FileNotFoundException fnfe){
			alarm = new Alarm();
			Calendar cal = new GregorianCalendar();
			Date dateAlarm = RSSFeed.getFirstDate();
			dateAlarm.setMinutes(dateAlarm.getMinutes()-Integer.parseInt(sharedPrefs.getString("alarm", "10")));
			cal.setTime(dateAlarm);
			alarm.setActive(false);
			alarm.setHeure(cal.get(Calendar.HOUR_OF_DAY));
			alarm.setDay(cal.get(Calendar.DAY_OF_MONTH));
			alarm.setMinute(cal.get(Calendar.MINUTE));
		}
		catch(IOException ioe) {
			ioe.printStackTrace();
		}
		catch(ClassNotFoundException cnfe) {
			cnfe.printStackTrace();
		}
	}   
	/**
	 * Job de planification de l'alarme
	 */
	private void planifierAlarm() {
		//Récupération de l'instance du service AlarmManager.
		AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

		//On instancie l'Intent qui va étre appelé au moment du alarme.
		Intent intent = new Intent(this, AlarmReceiver.class);

		//On créer le pending Intent qui identifie l'Intent de alarme avec un ID et un/des flag(s)
		PendingIntent pendingintent = PendingIntent.getBroadcast(this, ALARM_ID, intent, 0);

		//On annule l'alarm pour replanifier si besoin
		am.cancel(pendingintent);

		//La on va déclencher un calcul pour connaitre le temps qui nous sépare de la prochaine alarme.
		Calendar alarme  = Calendar.getInstance();
		alarme.set(Calendar.HOUR_OF_DAY, alarm.getHeure());
		alarme.set(Calendar.MINUTE, alarm.getMinute());
		alarme.set(Calendar.DAY_OF_MONTH, alarm.getDay());

		Calendar cal = Calendar.getInstance();
		alarme.set(Calendar.SECOND, 0);
		cal.set(Calendar.SECOND, 0);
		long diff = alarme.getTimeInMillis() - cal.getTimeInMillis();

		//On ajoute le alarme au service de l'AlarmManager
		am.set(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis() + diff, pendingintent);
		// 		Toast.makeText(this, "Alarme programmée le " + 
		// 				alarme.get(Calendar.DAY_OF_MONTH) + " à " + 
		// 				alarme.get(Calendar.HOUR_OF_DAY) + ":" + + 
		// 				alarme.get(Calendar.MINUTE), Toast.LENGTH_SHORT).show();
		if(DEBUG) System.out.println("Alarme programmée le " + 
				alarme.get(Calendar.DAY_OF_MONTH) + " à " + 
				alarme.get(Calendar.HOUR_OF_DAY) + ":" + + 
				alarme.get(Calendar.MINUTE));
	}
	public RSSFeed getFeed() {
		return feed;
	}
	public void setFeed(RSSFeed feed) {
		this.feed = feed;
	}
	/**
	 * @return the listPrint
	 */
	public boolean isListPrint() {
		return listPrint;
	}
	/**
	 * @param listPrint the listPrint to set
	 */
	public void setListPrint(boolean listPrint) {
		this.listPrint = listPrint;
		mProgressDialog.dismiss();
		TextView textview = (TextView) findViewById(R.id.content_rssActivity);
		textview.setText("");
	}
	/**
	 * @return the taskEnd
	 */
	public boolean isTaskEnd() {
		return taskEnd;
	}
	/**
	 * @param taskEnd the taskEnd to set
	 */
	public void setTaskEnd(boolean taskEnd) {
		this.taskEnd = taskEnd;
	}
}